#ifndef _SOCKET_PROGRAMMER_H_
#define _SOCKET_PROGRAMMER_H_
#include <arpa/inet.h>
#include <iostream>
#include <stdio.h>
#include <string>
#include <unistd.h>

constexpr int max_listen_num = 128;

void display_client_info(uint32_t addr_family, sockaddr *client_addr)
{
    char address[32] = {0};
    uint16_t port = 0;
    std::string display_info = "client information:\n";

    switch (addr_family) {
    case AF_INET: {
        const sockaddr_in *ipv4_addr = reinterpret_cast<sockaddr_in *>(client_addr);
        if (inet_ntop(AF_INET, &ipv4_addr->sin_addr, address, sizeof(address)) == nullptr) {
            display_info += "Invalid IPv4 address\n";
        } else {
            display_info += "IPv4: " + std::string(address) + '\n';
        }
        port = ntohs(ipv4_addr->sin_port);
        break;
    }
    case AF_INET6: {
        const sockaddr_in6 *ipv6_addr = reinterpret_cast<sockaddr_in6 *>(client_addr);
        if (inet_ntop(AF_INET6, &ipv6_addr->sin6_addr, address, sizeof(address)) == nullptr) {
            display_info += "Invalid IPv6 address\n";
        } else {
            display_info += "IPv6: " + std::string(address) + '\n';
        }
        port = ntohs(ipv6_addr->sin6_port);
        break;
    }
    default:
        display_info += "Unknown address family\n";
        break;
    }

    std::cout << display_info;
    std::cout << "client port: " << port << std::endl;
}

/* 如果客户端不需要指定ip，则选用此普通的通信类 */
class tcpsocket
{
  private:
    /* Just client can use fd */
    int fd = 0;
    uint32_t addr_family = 0;
    sockaddr *server_addr = nullptr;

  public:
    tcpsocket(uint32_t addr_family)
    {
        switch (addr_family) {
        case AF_INET:
            server_addr = reinterpret_cast<sockaddr *>(new sockaddr_in);
            break;
        case AF_INET6:
            server_addr = reinterpret_cast<sockaddr *>(new sockaddr_in6);
            break;
        default:
            break;
        }
        this->addr_family = addr_family;

        this->fd = socket(addr_family, SOCK_STREAM, 0);
        if (this->fd == -1) {
            perror("Fail to create socket");
            return;
        }
        std::cout << "Create client socket successfully" << std::endl;
    }
    virtual ~tcpsocket()
    {
        close(this->fd);
        delete server_addr;
    }
    int connect_host(const std::string addr, int port);
    int get_fd() { return fd; }
    sockaddr *get_server_addr() { return server_addr; }
    uint32_t get_addr_family() { return this->addr_family; }
};

/* 可用作客户端或者服务器 */
class advanced_client : public tcpsocket
{
  private:
    sockaddr *client_addr = nullptr;
    /* Just server can use cfd(connect fd) */
    int cfd = 0;
    socklen_t client_addr_len = 0;

  public:
    advanced_client(int addr_family) : tcpsocket(addr_family)
    {
        switch (addr_family) {
        case AF_INET:
            client_addr = reinterpret_cast<sockaddr *>(new sockaddr_in);
            client_addr_len = sizeof(sockaddr_in);
            std::cout << "创建IPv4通信\n";
            break;
        case AF_INET6:
            client_addr = reinterpret_cast<sockaddr *>(new sockaddr_in6);
            client_addr_len = sizeof(sockaddr_in6);
            std::cout << "创建IPv6通信\n";
            break;
        default:
            break;
        }

        std::cout << "Create client sockaddr successfully" << std::endl;
    }
    int bind_client_ip(const std::string client_ip, uint16_t port);
    int tcpserver_bind_and_listen(const std::string addr, int port);
    int tcpserver_accept();
    sockaddr *get_client_addr() { return client_addr; }
    int get_cfd() { return cfd; }
    ~advanced_client() { delete client_addr; }
};

#endif